﻿using System.Web;
using AutoTest.Business.IServices;
using AutoTest.Business.IServices.Auth;
using AutoTest.Business.IServices.Common;
using AutoTest.Business.Model;
using AutoTest.Business.Vo.UserInfo;
using AutoTest.Common;
using AutoTest.Common.Extension;
using AutoTest.Common.UtilsHelper;
using AutoTest.Domain;
using AutoTest.Domain.Entities;
using AutoTest.Domain.Enums;
using AutoTest.Framework.Exceptions;
using AutoTest.Framework.Extensions;
using AutoTest.Framework.Ioc;
using EasyTool;
using SqlSugar;

namespace AutoTest.Business.Services.Auth
{
    /// <summary>
    /// 授权服务
    /// </summary>
    public class AuthService(
          IServiceProvider serviceProvider
        , IRedisCacheService redisCacheService
        , IUserService userInfoService
        , ISqlSugarClient db
        ) : IAuthService, IScoped
    {
        private readonly IServiceProvider _serviceProvider = serviceProvider;
        private readonly IRedisCacheService _redisCacheService = redisCacheService;
        private readonly IUserService _userInfoService = userInfoService;
        private readonly ISqlSugarClient _db = db;

        /// <summary>
        /// 获取授权地址
        /// </summary>
        /// <param name="platform"></param>
        /// <param name="authCallBackUrl"></param>
        /// <param name="returnUrl"></param>
        /// <param name="invitecode"></param>
        /// <returns></returns>
        public async Task<string> GetAuthUrlAsync(EnumPlatform platform, string authCallBackUrl, string returnUrl, string invitecode)
        {
            var service = _serviceProvider.GetNamedService<IOpenAuthService>(platform.ToString());
            string id = IdUtil.UUIDString();
            string key = $"{AppConsts.REDIS_AUTH_CACHE_PREFIX}_{id}";
            var value = new AuthCacheModel() { ReturnUrl = returnUrl, Platform = platform, InviteCode = invitecode, AuthUrl = authCallBackUrl };
            _redisCacheService.Set(key, value);

            return await service.GetAuthUrlAsync(new Dictionary<string, object>() { { "state", id } });
        }

        /// <summary>
        /// 获取授权后跳转地址
        /// </summary>
        /// <param name="code"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public async Task<string> GetAuthCallBackUrlAsync(string code, string state)
        {
            string key = $"{AppConsts.REDIS_AUTH_CACHE_PREFIX}_{state}";
            AuthCacheModel model = _redisCacheService.Get<AuthCacheModel>(key);
            if (model.IsNull() || model.AuthUrl.IsEmpty()) return $"/open/auth-callback?code={code}&state={state}&invitecode={model?.InviteCode??""}";

            var service = _serviceProvider.GetNamedService<IOpenAuthService>(model.Platform.ToString());
            OpenUserInfoModel userModel = await service.GetOpenUserInfoAsync(code) ?? throw new BusinessException("获取用户信息失败");
            userModel.InviteCode = model.InviteCode;
            userModel.RetUrl = model.ReturnUrl;

            UserInfo userInfo = await _userInfoService.CheckUserInfoAsync(userModel, true);
            userModel.IsNewUser = userInfo.IsNull();

            string authUrl = model.AuthUrl;
            string authInfo;

            if (userModel.IsNewUser)
            {
                authInfo = HttpUtility.UrlEncode(userModel.ToJson(true).ToBase64());
            }
            else
            {
                var dto = await _userInfoService.LoginUserAsync(userInfo);
                dto.ReturnUrl = model.ReturnUrl;  //userModel.AccountJumpUrl;
                authInfo = HttpUtility.UrlEncode(dto.ToJson(true).ToBase64());
            }
            int isNew = userModel.IsNewUser ? 1 : 0;
            if (authUrl.Contains('?'))
            {
                authUrl += $"&isnew={isNew}&info={authInfo}";
            }
            else
            {
                authUrl += $"?isnew={isNew}&info={authInfo}";
            }

            return await Task.FromResult(authUrl);
        }

        /// <summary>
        /// 开房平台获取用户信息登录
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<LoginUserVo> OpenLoginAsync(OpenUserInfoModel model)
        {
            UserInfo userInfo = await ProcessOpenUserInfo(model, model.Platform, model.InviteCode);
            var dto = await _userInfoService.LoginUserAsync(userInfo);
            return dto;
        }
        /// <summary>
        /// 模拟登录
        /// </summary>
        /// <returns></returns>
        public async Task<LoginUserVo> TestLogin()
        {
            var userInfo = await _db.Queryable<UserInfo>().FirstAsync();
            if (userInfo != null)
            {
                return await _userInfoService.LoginUserAsync(userInfo);
            }
            return null!;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="platform"></param>
        /// <param name="inviteCode"></param>
        /// <returns></returns>
        private async Task<UserInfo> ProcessOpenUserInfo(OpenUserInfoModel model, EnumPlatform platform, string inviteCode)
        {

            OpenInfo openInfo = null!;
            UserInfo user = null!;
            long userid = IdHelper.NextId();

           
            var result = await _db.Ado.UseTranAsync<UserInfo>( async () =>
            {
                #region 处理OpenInfo
                if (model.UnionId.IsNotEmpty())
                {
                    openInfo = await db.Queryable<OpenInfo>().FirstAsync(c => c.UnionId == model.UnionId); 
                }
                if (openInfo.IsNull())
                {
                    openInfo = await db.Queryable<OpenInfo>().FirstAsync(c => c.OpenId == model.OpenId); 
                }
                if (openInfo.IsNull())
                {
                    openInfo = new OpenInfo()
                    {
                        Id = IdHelper.NextId(),
                        CreateTime = DateTime.Now,
                        LastUpdateTime = DateTime.Now,
                        OpenId = model.OpenId,
                        OpenNickName = model.NickName,
                        Platform = platform.ToString(),
                        UnionId = model.UnionId,
                        UserId = userid,
                        IsSubscrible = false,
                    };
                    db.Insertable(openInfo).ExecuteCommand();
                }
                else
                {
                    if (openInfo.UserId > 0)
                    {
                        userid = openInfo.UserId;
                    }
                    openInfo.OpenNickName = model.NickName;
                    openInfo.IsSubscrible = model.IsSubscrible;
                    db.Updateable(openInfo).UpdateColumns(c => c.UserId).ExecuteCommand();
                }
                #endregion

                #region 处理UserInfo
                if (userid > 0)
                {
                    user = await db.Queryable<UserInfo>().FirstAsync(c => c.Id == userid); //await _repository.FirstOrDefaultAsync<UserInfo>(c => c.Id == userid);
                    long inviteId = 0;
                    long parentparentid = 0;
                    long rootid = 0;
                    string invitePath = string.Empty;

                    if (user.IsNull())
                    {
                        string code = RandomUtil.RandomString(6);
                        user = new UserInfo()
                        {
                            City = model.City,
                            Country = model.Country,
                            CreditCard = string.Empty,
                            CreateTime = DateTime.Now,
                            Email = string.Empty,
                            IconUrl = model.HeadImgUrl,
                            Id = userid,
                            NickName = model.NickName,
                            InviteCode = code,
                            ParentId = inviteId,
                            ParentParentId = parentparentid,
                            RootId = rootid,
                            ParentPath = invitePath,
                            Password = EncryptHelper.Md532(code),
                            Phone = string.Empty,
                            Province = model.Province,
                            RealName = string.Empty,
                            Sex = model.Sex,
                            SexName = (model.Sex).GetDescription(),
                            Status = EnumStatus.Enable,
                            UserName = string.Empty,
                            ValidTime = DateTime.Now.Date,
                            IsCoper = false,
                            PayCodeUrl = string.Empty
                        };
                        //await _repository.AddEntityAsync(user);
                        await db.Insertable(user).ExecuteCommandAsync();
                    }
                    else
                    {
                        user.NickName = model.NickName;
                        user.IconUrl = model.HeadImgUrl;
                        user.Province = model.Province;
                        user.City = model.City;
                        user.Country = model.Country;
                        //await _repository.UpdateEntityAsync(user);
                        await db.Updateable(user).ExecuteCommandAsync();
                    }

                    //考虑到建立关系和创建用户会有一定的延迟。
                    //所以我确定在一小时内尽量保证能够确定这个关系
                    if (user.ParentPath.IsEmpty() && user.ParentId <= 0 && user.CreateTime.AddMinutes(60) > DateTime.Now && inviteCode.IsNotEmpty())
                    {
                        UserInfo parentUser = await db.Queryable<UserInfo>().FirstAsync(c => c.InviteCode == inviteCode);  
                        if (parentUser.IsNotNull())
                        {
                            inviteId = parentUser.Id;
                            parentparentid = parentUser.ParentId;
                            rootid = parentUser.RootId > 0 ? parentUser.RootId : parentUser.Id;
                            var pathList = new List<string>();
                            if (parentUser.ParentPath.IsNotEmpty())
                            {
                                pathList.Add(parentUser.ParentPath);
                            }
                            pathList.Add(parentUser.Id.ToString());
                            invitePath = pathList.StrJoin("-");

                            user.ParentId = inviteId;
                            user.ParentParentId = parentparentid;
                            user.RootId = rootid;
                            user.ParentPath = invitePath;
                            await db.Updateable(user).ExecuteCommandAsync();
                        }
                    }

                }

                #endregion

                return user;
            });
            if (result.IsSuccess)
            {
                return result.Data;
            }
            else throw result.ErrorException;

        }
    }
}
